home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-05 | 35.7 KB | 1,626 lines | [TEXT/CWIE] |
- /*********************************************************************
- Project : GUSI - Grand Unified Socket Interface
- File : GUSIUnix.cp - Implementation of Unix domain calls
- Author : Matthias Neeracher
- Language : MPW C/C++
-
- $Log: GUSIUnix.cp,v $
- Revision 1.3 1994/12/30 20:20:19 neeri
- Add (untested) PowerPC support.
-
- Revision 1.2 1994/08/10 00:00:35 neeri
- Sanitized for universal headers.
-
- Revision 1.1 1994/02/25 02:31:11 neeri
- Initial revision
-
- Revision 0.13 1993/02/07 00:00:00 neeri
- New configuration scheme
-
- Revision 0.12 1993/01/17 00:00:00 neeri
- Be more careful about User interrupts
-
- Revision 0.11 1992/11/15 00:00:00 neeri
- Rename GUSIFSp_P.h to TFileSpec.h (there we go again)
-
- Revision 0.10 1992/09/13 00:00:00 neeri
- Always complete write
-
- Revision 0.9 1992/09/12 00:00:00 neeri
- Renamed Paths.h to GUSIFSp_P.h
-
- Revision 0.8 1992/08/10 00:00:00 neeri
- select() for accept/connect
-
- Revision 0.7 1992/07/26 00:00:00 neeri
- Error in using memccpy()
-
- Revision 0.6 1992/07/13 00:00:00 neeri
- In spirit of Unix implementation, use file, not hash table
-
- Revision 0.5 1992/05/21 00:00:00 neeri
- Implemented select()
-
- Revision 0.4 1992/04/24 00:00:00 neeri
- Introducing UnixStreamSocket, UnixDgramSocket
-
- Revision 0.3 1992/04/20 00:00:00 neeri
- C++ rewrite
-
- Revision 0.2 1992/04/18 00:00:00 neeri
- On with the show, good health to you
-
- Revision 0.1 1992/03/31 00:00:00 neeri
- unix domain socket calls
-
- *********************************************************************/
-
- #include "GUSIFile_P.h"
- #include <TFileSpec.h>
-
- #include <Processes.h>
- #include <Resources.h>
- #include <LowMem.h>
- #include <Finder.h>
-
- /*
- * In a fit of hubris, I had assumed that the format of vtables in a C++
- * object would remain constant forever, and furthermore hadn't paid
- * attention to issues of PowerPC compatibility.
- *
- * To remedy the situation, I have to emulate the original CFront generated
- * code to some degree.
- */
-
- #if GENERATINGPOWERPC || defined(__MWERKS__)
- #define EMULATE_CFRONT
- #define EMULATE_VIRTUAL
- #else
- #define EMULATE_VIRTUAL virtual
- #endif
-
- #if GENERATING68K
- #pragma segment GUSIUnix
- #endif
-
- class UnixSocketDomain : public SocketDomain {
- public:
- UnixSocketDomain() : SocketDomain(AF_UNIX) { }
-
- Socket * socket(int type, short protocol);
- int choose(
- int type,
- char * prompt,
- void * constraint,
- int flags,
- void * name,
- int * namelen);
- };
-
- static UnixSocketDomain UnixSockets;
-
- class UnixSocket; // That's what this file's all about
- class UnixStreamSocket;
- class UnixDgramSocket;
-
- #if PRAGMA_ALIGN_SUPPORTED
- #pragma options align=mac68k
- #endif
- struct UnixSocketAddr : TFileSpec {
- Boolean valid;
- Boolean owned;
-
- UnixSocketAddr();
- UnixSocketAddr(TFileSpec spec);
- };
- #if PRAGMA_ALIGN_SUPPORTED
- #pragma options align=reset
- #endif
-
- // The interface of this class should never be changed now the first version
- // of GUSI is released. All further changes should be done by making a subclass.
- // The Version() method must return *increasing* version numbers.
-
- // Version 2 adds support for aborting a connection, see below
-
- #if PRAGMA_ALIGN_SUPPORTED
- #pragma options align=mac68k
- #endif
- #ifdef EMULATE_CFRONT
- class UnixChannel {
- #else
- class UnixChannel : public SingleObject {
- #endif
- UnixSocketAddr address;
-
- void UnBind();
- protected:
- UnixSocket * sock;
- public:
- UnixChannel * nextListener;
- int errno;
- #ifdef EMULATE_CFRONT
- UniversalProcPtr * emulated_vtable;
- #endif
-
- UnixChannel(UnixSocket * owner);
- EMULATE_VIRTUAL ~UnixChannel();
-
- EMULATE_VIRTUAL int Version();
-
- EMULATE_VIRTUAL Boolean Bind(UnixSocketAddr & addr);
- EMULATE_VIRTUAL Boolean Connect(UnixChannel * ch);
- EMULATE_VIRTUAL Boolean Accept(UnixChannel * ch);
-
- EMULATE_VIRTUAL int Read(void * buffer, int len);
- EMULATE_VIRTUAL int Write(void * buffer, int len);
- EMULATE_VIRTUAL int Send(UnixChannel * from, void * buffer, int len);
- EMULATE_VIRTUAL int ReadAvail();
- EMULATE_VIRTUAL int WriteAvail();
- EMULATE_VIRTUAL int BufSize();
- EMULATE_VIRTUAL void DiscardRead(int len);
- EMULATE_VIRTUAL void ShutDown(int how);
- EMULATE_VIRTUAL void Disconnect();
-
- EMULATE_VIRTUAL int GUSI_error(int err);
-
- EMULATE_VIRTUAL UnixSocketAddr &
- Address();
- };
-
- class UnixChannel2 : public UnixChannel {
- public:
- UnixChannel2(UnixSocket * owner);
-
- #ifndef EMULATE_CFRONT
- int Version();
- #endif
- EMULATE_VIRTUAL void Orphan();
- EMULATE_VIRTUAL void AbortConnect(UnixChannel * ch);
- };
- #if PRAGMA_ALIGN_SUPPORTED
- #pragma options align=reset
- #endif
-
-
- #ifdef EMULATE_CFRONT
- class UnixChannel;
-
- #if GENERATING68K
- #pragma pointers_in_D0
- #endif
-
- void Delete_UnixChannel(UnixChannel * chan)
- {
- delete chan;
- }
-
- int Version_UnixChannel(UnixChannel * chan)
- {
- return chan->Version();
- }
-
- Boolean Bind_UnixChannel(UnixChannel * chan, UnixSocketAddr & addr)
- {
- return chan->Bind(addr);
- }
-
- Boolean Connect_UnixChannel(UnixChannel * chan, UnixChannel * ch)
- {
- return chan->Connect(ch);
- }
-
- Boolean Accept_UnixChannel(UnixChannel * chan, UnixChannel * ch)
- {
- return chan->Accept(ch);
- }
-
- int Read_UnixChannel(UnixChannel * chan, void * buffer, int len)
- {
- return chan->Read(buffer, len);
- }
-
- int Write_UnixChannel(UnixChannel * chan, void * buffer, int len)
- {
- return chan->Write(buffer, len);
- }
-
- int Send_UnixChannel(UnixChannel * chan, UnixChannel * from, void * buffer, int len)
- {
- return chan->Send(from, buffer, len);
- }
-
- int ReadAvail_UnixChannel(UnixChannel * chan)
- {
- return chan->ReadAvail();
- }
-
- int WriteAvail_UnixChannel(UnixChannel * chan)
- {
- return chan->WriteAvail();
- }
-
- int BufSize_UnixChannel(UnixChannel * chan)
- {
- return chan->BufSize();
- }
-
- void DiscardRead_UnixChannel(UnixChannel * chan, int len)
- {
- chan->DiscardRead(len);
- }
-
- void ShutDown_UnixChannel(UnixChannel * chan, int how)
- {
- chan->ShutDown(how);
- }
-
- void Disconnect_UnixChannel(UnixChannel * chan)
- {
- chan->Disconnect();
- }
-
- int GUSI_error_UnixChannel(UnixChannel * chan, int err)
- {
- return chan->GUSI_error(err);
- }
-
- UnixSocketAddr & Address_UnixChannel(UnixChannel * chan)
- {
- return chan->Address();
- }
-
- void Orphan_UnixChannel(UnixChannel2 * chan)
- {
- chan->Orphan();
- }
-
- void AbortConnect_UnixChannel(UnixChannel2 * chan, UnixChannel * ch)
- {
- chan->AbortConnect(ch);
- }
-
- #if GENERATING68K
- #pragma pointers_in_A0
- #endif
-
- #if GENERATINGCFM
- enum {
- piDelete =
- kCStackBased
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
- piVersion =
- kCStackBased
- | RESULT_SIZE(kFourByteCode)
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
- piBind =
- kCStackBased
- | RESULT_SIZE(kOneByteCode)
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(2, kFourByteCode),
- piConnect =
- kCStackBased
- | RESULT_SIZE(kOneByteCode)
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(2, kFourByteCode),
- piAccept =
- kCStackBased
- | RESULT_SIZE(kOneByteCode)
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(2, kFourByteCode),
- piRead =
- kCStackBased
- | RESULT_SIZE(kFourByteCode)
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(2, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(3, kFourByteCode),
- piWrite =
- kCStackBased
- | RESULT_SIZE(kFourByteCode)
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(2, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(3, kFourByteCode),
- piSend =
- kCStackBased
- | RESULT_SIZE(kFourByteCode)
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(2, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(3, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(4, kFourByteCode),
- piReadAvail =
- kCStackBased
- | RESULT_SIZE(kFourByteCode)
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
- piWriteAvail =
- kCStackBased
- | RESULT_SIZE(kFourByteCode)
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
- piBufSize =
- kCStackBased
- | RESULT_SIZE(kFourByteCode)
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
- piDiscardRead =
- kCStackBased
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(2, kFourByteCode),
- piShutDown =
- kCStackBased
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(2, kFourByteCode),
- piDisconnect =
- kCStackBased
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
- piGUSI_error =
- kCStackBased
- | RESULT_SIZE(kFourByteCode)
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(2, kFourByteCode),
- piAddress =
- kCStackBased
- | RESULT_SIZE(kFourByteCode)
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
- piOrphan =
- kCStackBased
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
- piAbortConnect =
- kCStackBased
- | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
- | STACK_ROUTINE_PARAMETER(2, kFourByteCode)
- };
-
- RoutineDescriptor rdDelete = BUILD_ROUTINE_DESCRIPTOR(piDelete, Delete_UnixChannel);
- RoutineDescriptor rdVersion = BUILD_ROUTINE_DESCRIPTOR(piVersion, Version_UnixChannel);
- RoutineDescriptor rdBind = BUILD_ROUTINE_DESCRIPTOR(piBind, Bind_UnixChannel);
- RoutineDescriptor rdConnect = BUILD_ROUTINE_DESCRIPTOR(piConnect, Connect_UnixChannel);
- RoutineDescriptor rdAccept = BUILD_ROUTINE_DESCRIPTOR(piAccept, Accept_UnixChannel);
- RoutineDescriptor rdRead = BUILD_ROUTINE_DESCRIPTOR(piRead, Read_UnixChannel);
- RoutineDescriptor rdWrite = BUILD_ROUTINE_DESCRIPTOR(piWrite, Write_UnixChannel);
- RoutineDescriptor rdSend = BUILD_ROUTINE_DESCRIPTOR(piSend, Send_UnixChannel);
- RoutineDescriptor rdReadAvail = BUILD_ROUTINE_DESCRIPTOR(piReadAvail, ReadAvail_UnixChannel);
- RoutineDescriptor rdWriteAvail = BUILD_ROUTINE_DESCRIPTOR(piWriteAvail, WriteAvail_UnixChannel);
- RoutineDescriptor rdBufSize = BUILD_ROUTINE_DESCRIPTOR(piBufSize, BufSize_UnixChannel);
- RoutineDescriptor rdDiscardRead = BUILD_ROUTINE_DESCRIPTOR(piDiscardRead, DiscardRead_UnixChannel);
- RoutineDescriptor rdShutDown = BUILD_ROUTINE_DESCRIPTOR(piShutDown, ShutDown_UnixChannel);
- RoutineDescriptor rdDisconnect = BUILD_ROUTINE_DESCRIPTOR(piDisconnect, Disconnect_UnixChannel);
- RoutineDescriptor rdGUSI_error = BUILD_ROUTINE_DESCRIPTOR(piGUSI_error, GUSI_error_UnixChannel);
- RoutineDescriptor rdAddress = BUILD_ROUTINE_DESCRIPTOR(piAddress, Address_UnixChannel);
- RoutineDescriptor rdOrphan = BUILD_ROUTINE_DESCRIPTOR(piOrphan, Orphan_UnixChannel);
- RoutineDescriptor rdAbortConnect = BUILD_ROUTINE_DESCRIPTOR(piAbortConnect, AbortConnect_UnixChannel);
-
- UniversalProcPtr UnixChannel_EmulatedVTable[] = {
- 0,
- &rdDelete,
- &rdVersion,
- &rdBind,
- &rdConnect,
- &rdAccept,
- &rdRead,
- &rdWrite,
- &rdSend,
- &rdReadAvail,
- &rdWriteAvail,
- &rdBufSize,
- &rdDiscardRead,
- &rdShutDown,
- &rdDisconnect,
- &rdGUSI_error,
- &rdAddress,
- &rdOrphan,
- &rdAbortConnect,
- 0,
- };
- #else
- UniversalProcPtr UnixChannel_EmulatedVTable[] = {
- 0,
- UniversalProcPtr(Delete_UnixChannel),
- UniversalProcPtr(Version_UnixChannel),
- UniversalProcPtr(Bind_UnixChannel),
- UniversalProcPtr(Connect_UnixChannel),
- UniversalProcPtr(Accept_UnixChannel),
- UniversalProcPtr(Read_UnixChannel),
- UniversalProcPtr(Write_UnixChannel),
- UniversalProcPtr(Send_UnixChannel),
- UniversalProcPtr(ReadAvail_UnixChannel),
- UniversalProcPtr(WriteAvail_UnixChannel),
- UniversalProcPtr(BufSize_UnixChannel),
- UniversalProcPtr(DiscardRead_UnixChannel),
- UniversalProcPtr(ShutDown_UnixChannel),
- UniversalProcPtr(Disconnect_UnixChannel),
- UniversalProcPtr(GUSI_error_UnixChannel),
- UniversalProcPtr(Address_UnixChannel),
- UniversalProcPtr(Orphan_UnixChannel),
- UniversalProcPtr(AbortConnect_UnixChannel),
- 0,
- };
- #endif
-
- #endif
-
- #ifdef EMULATE_CFRONT
- #if GENERATINGCFM
- #define CUP CallUniversalProc
- #define EMUL_Delete(p) CUP(p->emulated_vtable[1], piDelete, p)
- #define EMUL_Version(p) (int) CUP(p->emulated_vtable[2], piVersion, p)
- #define EMUL_Connect(p, x) (Boolean) CUP(p->emulated_vtable[4], piConnect, p, x)
- #define EMUL_Accept(p, x) (Boolean) CUP(p->emulated_vtable[5], piAccept, p, x)
- #define EMUL_Write(p, x, y) (int) CUP(p->emulated_vtable[7], piWrite, p, x, y)
- #define EMUL_Send(p, x, y, z) (int) CUP(p->emulated_vtable[8], piSend, p, x, y, z)
- #define EMUL_ReadAvail(p) (int) CUP(p->emulated_vtable[9], piReadAvail, p)
- #define EMUL_WriteAvail(p) (int) CUP(p->emulated_vtable[10], piWriteAvail, p)
- #define EMUL_BufSize(p) (int) CUP(p->emulated_vtable[11], piBufSize, p)
- #define EMUL_Disconnect(p) CUP(p->emulated_vtable[14], piDisconnect, p)
- #define EMUL_Address(p) (* (UnixSocketAddr *) CUP(p->emulated_vtable[16], piAddress, p))
- #define EMUL_AbortConnect(p, x) CUP(p->emulated_vtable[18], piAbortConnect, p, x)
- #else
- #pragma pointers_in_D0
- inline void EMUL_Delete(UnixChannel * p)
- {
- ((void (*)(UnixChannel *))p->emulated_vtable[1])(p);
- }
-
- inline int EMUL_Version(UnixChannel * p)
- {
- return ((int (*)(UnixChannel *))p->emulated_vtable[2])(p);
- }
-
- inline Boolean EMUL_Connect(UnixChannel * p, UnixChannel * x)
- {
- return ((Boolean (*)(UnixChannel *, UnixChannel *))p->emulated_vtable[4])(p, x);
- }
-
- inline Boolean EMUL_Accept(UnixChannel * p, UnixChannel * x)
- {
- return ((Boolean (*)(UnixChannel *, UnixChannel *))p->emulated_vtable[5])(p, x);
- }
-
- inline int EMUL_Write(UnixChannel * p, void * x, int y)
- {
- return ((int (*)(UnixChannel *, void *, int))p->emulated_vtable[7])(p, x, y);
- }
-
- inline int EMUL_Send(UnixChannel * p, UnixChannel * x, void * y, int z)
- {
- return ((int (*)(UnixChannel *, UnixChannel *, void *, int))p->emulated_vtable[8])(p, x, y, z);
- }
-
- inline int EMUL_ReadAvail(UnixChannel * p)
- {
- return ((int (*)(UnixChannel *))p->emulated_vtable[9])(p);
- }
-
- inline int EMUL_WriteAvail(UnixChannel * p)
- {
- return ((int (*)(UnixChannel *))p->emulated_vtable[10])(p);
- }
-
- inline int EMUL_BufSize(UnixChannel * p)
- {
- return ((int (*)(UnixChannel *))p->emulated_vtable[11])(p);
- }
-
- inline void EMUL_Disconnect(UnixChannel * p)
- {
- ((void (*)(UnixChannel *))p->emulated_vtable[14])(p);
- }
-
- inline UnixSocketAddr & EMUL_Address(UnixChannel * p)
- {
- return ((UnixSocketAddr & (*)(UnixChannel *))p->emulated_vtable[16])(p);
- }
-
- inline void EMUL_AbortConnect(UnixChannel * p, UnixChannel * x)
- {
- ((void (*)(UnixChannel2 *, UnixChannel *))p->emulated_vtable[18])((UnixChannel2 *) p, x);
- }
-
- #pragma pointers_in_A0
- #endif
- #else
- #define EMUL_Delete(p) delete p
- #define EMUL_Version(p) p->Version()
- #define EMUL_Connect(p, x) p->Connect(x)
- #define EMUL_Accept(p, x) p->Accept(x)
- #define EMUL_Write(p, x, y) p->Write(x, y)
- #define EMUL_Send(p, x, y, z) p->Send(x, y, z)
- #define EMUL_ReadAvail(p) p->ReadAvail()
- #define EMUL_WriteAvail(p) p->WriteAvail()
- #define EMUL_BufSize(p) p->BufSize()
- #define EMUL_Disconnect(p) p->Disconnect()
- #define EMUL_Address(p) p->Address()
- #define EMUL_AbortConnect(p, x) ((UnixChannel2 *)p)->AbortConnect(x)
- #endif
-
- #if PRAGMA_ALIGN_SUPPORTED
- #pragma options align=mac68k
- #endif
- class UnixSocket : public Socket {
- friend class UnixChannel;
- friend class UnixChannel2;
-
- #if GENERATING68K
- Ptr processA5; /* Our A5 world */
- #endif
- protected:
- char status;
- char state;
- Boolean nonblocking;
- char protocol;
- Ptr readBuf;
- short readBufSize;
- short readPos;
- short validBytes;
- short curListener;
- short maxListener;
- UnixChannel * chan;
- UnixChannel * peer;
- UnixChannel * firstListener;
- UnixChannel * lastListener;
-
- UnixSocket(short prot);
- void defaultbind();
- public:
- void Ready();
-
- enum {channelUnknown, channelAncient, channelSupportsConnAbort};
-
- virtual int bind(void * name, int namelen);
- virtual int getsockname(void * name, int * namelen);
- virtual int getpeername(void * name, int * namelen);
- virtual int fcntl(unsigned int cmd, int arg);
- virtual int ioctl(unsigned int request, void *argp);
- virtual int shutdown(int how);
- virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
- virtual ~UnixSocket();
- };
-
-
- #if GENERATINGCFM
- inline void UnixSocket::Ready()
- {
- UnixSockets.Ready();
- }
- #endif
-
- class UnixStreamSocket : public UnixSocket {
- friend class UnixSocketDomain;
-
- UnixStreamSocket();
- public:
- int listen(int qlen);
- int connect(void * address, int addrlen);
- Socket * accept(void * address, int * addrlen);
- int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
- int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
-
- ~UnixStreamSocket();
- };
-
- class UnixDgramSocket : public UnixSocket {
- friend class UnixSocketDomain;
-
- UnixDgramSocket();
- public:
- int connect(void * address, int addrlen);
- int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
- int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
-
- ~UnixDgramSocket();
- };
- #if PRAGMA_ALIGN_SUPPORTED
- #pragma options align=reset
- #endif
-
-
- struct UnixSocketID {
- UnixChannel * chan;
-
- AddrBlock machine;
- ProcessSerialNumber process;
-
- UnixSocketID() {}
- UnixSocketID(UnixChannel * ch);
- Boolean Validate();
- };
-
- /********************** UnixSocketAddr members ***********************/
-
- inline UnixSocketAddr::UnixSocketAddr()
- : valid(false), owned(true)
- {
- }
-
- UnixSocketAddr::UnixSocketAddr(TFileSpec spec)
- : TFileSpec(spec), valid(false), owned(true)
- {
- }
-
- /************************ UnixSocket members ************************/
-
- static UnixSocketAddr * CanonizeName(void * name, int len);
- static void UncanonizeName(UnixSocketAddr & name, void * addr, int * addrlen);
- static UnixChannel * LookupName(UnixSocketAddr name);
-
- #if !GENERATINGCFM
- void UnixSocket::Ready()
- {
- long saveA5 = SetA5(long(processA5));
-
- UnixSockets.Ready();
-
- SetA5(saveA5);
- }
- #endif
-
- UnixSocket::UnixSocket(short prot)
- {
- GUSI_error(0);
-
- readBufSize = DEFAULT_BUFFER_SIZE;
- status = SOCK_STATUS_USED;
- state = SOCK_STATE_UNCONNECTED;
- nonblocking = false;
- protocol = prot;
- readPos = 0;
- validBytes = 0;
- curListener = 0;
- maxListener = 0;
- firstListener = nil;
- lastListener = nil;
- chan = nil;
- peer = nil;
- readBuf = NewPtr(readBufSize);
-
- if (!readBuf)
- GUSI_error(ENOMEM);
-
- #if !GENERATINGCFM
- processA5 = LMGetCurrentA5();
- #endif
- }
-
- UnixSocket::~UnixSocket()
- {
- if (readBuf)
- DisposPtr(readBuf);
-
- if (protocol == SOCK_STREAM)
- if (peer)
- EMUL_Disconnect(peer);
- else
- while (firstListener) {
- EMUL_Disconnect(firstListener);
-
- firstListener = firstListener->nextListener;
- }
-
- if (chan)
- delete chan;
- }
-
- void UnixSocket::defaultbind()
- {
- struct sockaddr_un addr;
-
- addr.sun_family = AF_UNIX;
- tmpnam(addr.sun_path);
-
- bind(&addr, strlen(addr.sun_path)+2);
- }
-
- int UnixSocket::fcntl(unsigned int cmd, int arg)
- {
- switch (cmd) {
- case F_GETFL:
- if (nonblocking)
- return FNDELAY;
- else
- return 0;
- case F_SETFL:
- if (arg & FNDELAY)
- nonblocking = true;
- else
- nonblocking = false;
-
- return 0;
- default:
- return GUSI_error(EOPNOTSUPP);
- }
- }
-
- int UnixSocket::ioctl(unsigned int request, void *argp)
- {
- switch (request) {
- case FIONBIO:
- nonblocking = (Boolean) *(long *) argp;
-
- return 0;
- case FIONREAD:
- if (chan)
- *(long *) argp = EMUL_ReadAvail(chan);
- else
- *(long *) argp = 0;
-
- return 0;
- default:
- return GUSI_error(EOPNOTSUPP);
- }
- }
-
- int UnixSocket::bind(void *sa_name, int sa_namelen)
- {
- UnixSocketAddr * addr;
-
- if (chan && chan->Address().valid)
- return GUSI_error(EINVAL);
-
- addr = CanonizeName(sa_name, sa_namelen);
-
- if (!addr)
- return -1;
-
- if (LookupName(*addr))
- return GUSI_error(EADDRINUSE);
-
- if (!chan && !(chan = new UnixChannel2(this)))
- return GUSI_error(ENOMEM);
-
- if (!chan->Bind(*addr))
- return GUSI_error(ENOMEM);
-
- return 0;
- }
-
- int UnixSocket::getsockname(void *name, int *namelen)
- {
- UncanonizeName(chan->Address(), name, namelen);
-
- return 0;
- }
-
- int UnixSocket::getpeername(void *name, int *namelen)
- {
- if (!peer)
- return GUSI_error(ENOTCONN);
-
- UncanonizeName(EMUL_Address(peer), name, namelen);
-
- return 0;
- }
-
- int UnixSocket::select(Boolean * canRead, Boolean * canWrite, Boolean *)
- {
- int goodies = 0;
-
- if (canRead)
- if ((state == SOCK_STATE_LIS_CON) || !chan || chan->ReadAvail()) {
- *canRead = true;
- ++goodies;
- }
-
- if (canWrite)
- if (!peer || EMUL_WriteAvail(peer)) {
- *canWrite = true;
- ++goodies;
- }
-
- return goodies;
- }
-
- int UnixSocket::shutdown(int how)
- {
- if (!chan)
- return GUSI_error(ENOTCONN);
-
- chan->ShutDown(how);
-
- return 0;
- }
-
- /********************* UnixStreamSocket members *********************/
-
- UnixStreamSocket::UnixStreamSocket()
- : UnixSocket(SOCK_STREAM)
- {
- }
-
- UnixStreamSocket::~UnixStreamSocket()
- {
- }
-
- int UnixStreamSocket::listen(int qlen)
- {
- if (state != SOCK_STATE_UNCONNECTED)
- return GUSI_error(EISCONN);
-
- state = SOCK_STATE_LISTENING;
- maxListener = qlen;
-
- return 0;
- }
-
- int UnixStreamSocket::connect(void *sa_name, int sa_namelen)
- {
- UnixSocketAddr * addr;
- UnixChannel * other;
-
- if (peer)
- return GUSI_error(EISCONN);
-
- addr = CanonizeName(sa_name, sa_namelen);
-
- if (!addr)
- return -1;
-
- other = LookupName(*addr);
-
- if (!other)
- return GUSI_error(ECONNREFUSED);
-
- if (!chan && !(chan = new UnixChannel2(this)))
- return GUSI_error(ENOMEM);
-
- if (!chan->Address().valid)
- defaultbind();
-
- if (!EMUL_Connect(other, chan))
- return GUSI_error(ECONNREFUSED);
-
- state = SOCK_STATE_CONNECTING;
-
- if (nonblocking)
- return GUSI_error(EINPROGRESS);
-
- SAFESPIN(state == SOCK_STATE_CONNECTING, SP_MISC, 0);
-
- if (state == SOCK_STATE_CONNECTED)
- return 0;
- else if (!errno)
- return GUSI_error(ECONNREFUSED);
-
- // User abort, a tricky situation. What we do depends on the peer channel
- // version.
-
- if (EMUL_Version(other) >= channelSupportsConnAbort) // The new way
- EMUL_AbortConnect(other, chan);
- else // The old way
- ((UnixChannel2 *) other)->UnixChannel2::Orphan(); // This type cast is safe
-
- return -1;
- }
-
- Socket * UnixStreamSocket::accept(void * address, int * addrlen)
- {
- UnixStreamSocket * newsock;
-
- if (state != SOCK_STATE_LISTENING && state != SOCK_STATE_LIS_CON)
- return (Socket *) GUSI_error_nil(ENOTCONN);
-
- restart:
- if (!curListener)
- if (nonblocking)
- return (Socket *) GUSI_error_nil(EWOULDBLOCK);
- else
- SPINP(state == SOCK_STATE_LISTENING, SP_MISC, 0);
-
- if (!curListener)
- return (Socket *) GUSI_error_nil(EINVAL); // I *really* hope this won't happen
-
- newsock = new UnixStreamSocket;
-
- if (!newsock)
- return (Socket *) GUSI_error_nil(ENOMEM);
-
- newsock->state = SOCK_STATE_CONNECTED;
- newsock->peer = firstListener;
- newsock->chan = new UnixChannel2(newsock);
-
- if (!newsock->chan) {
- delete newsock;
-
- return (Socket *) GUSI_error_nil(ENOMEM);
- }
-
- newsock->chan->Address() = chan->Address();
- newsock->chan->Address().owned = false;
-
- firstListener = firstListener->nextListener;
-
- if (!firstListener)
- lastListener = nil;
-
- if (!--curListener)
- state = SOCK_STATE_LISTENING;
-
- if (EMUL_Accept(newsock->peer, newsock->chan) == -1) {
- newsock->peer = nil;
-
- delete newsock;
-
- goto restart;
- }
-
- UncanonizeName(EMUL_Address(newsock->peer), address, addrlen);
-
- return newsock;
- }
-
- int UnixStreamSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int *)
- {
- int avail;
-
- if (flags || from)
- return GUSI_error(EOPNOTSUPP);
- if (!chan || !peer)
- return GUSI_error(ENOTCONN);
-
- if ((avail = chan->ReadAvail()) == -1)
- if (chan->errno == ESHUTDOWN)
- return 0;
- else
- return GUSI_error(chan->errno);
-
- if (nonblocking && !avail)
- return GUSI_error(EWOULDBLOCK);
-
- errno = 0;
- SPIN(!(avail = chan->Read(buffer, buflen)), SP_STREAM_READ, 0);
- if (avail == -1 && !errno)
- if (chan->errno == ESHUTDOWN)
- return 0;
- else
- GUSI_error(chan->errno);
-
- return avail;
- }
-
- int UnixStreamSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
- {
- int avail;
- int done;
-
- if (flags || to)
- return GUSI_error(EOPNOTSUPP);
- if (!chan || !peer)
- return GUSI_error(ENOTCONN);
-
- if ((avail = EMUL_WriteAvail(peer)) == -1)
- return GUSI_error(peer->errno);
-
- if (nonblocking && !avail)
- return GUSI_error(EWOULDBLOCK);
-
- for (
- done = errno = 0;
- !errno && buflen;
- buflen -= avail, buffer = Ptr(buffer) + avail
- ) {
- SPIN(!(avail = EMUL_Write(peer, buffer, buflen)), SP_STREAM_WRITE, 0);
- if (avail == -1) {
- if (!errno)
- GUSI_error(peer->errno);
-
- break;
- }
-
- done += avail;
-
- if (nonblocking)
- break;
- }
-
- return done ? done : (buflen ? -1 : 0);
- }
-
- /********************* UnixDgramSocket members **********************/
-
- UnixDgramSocket::UnixDgramSocket()
- : UnixSocket(SOCK_DGRAM)
- {
- }
-
- UnixDgramSocket::~UnixDgramSocket()
- {
- }
-
- int UnixDgramSocket::connect(void *sa_name, int sa_namelen)
- {
- UnixSocketAddr * addr;
-
- addr = CanonizeName(sa_name, sa_namelen);
-
- if (!addr)
- return -1;
-
- peer = LookupName(*addr);
-
- if (!peer)
- return GUSI_error(ECONNREFUSED);
-
- state = SOCK_STATE_CONNECTED;
-
- return 0;
- }
-
- int UnixDgramSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen)
- {
- UnixChannel * partner;
- int length;
- int avail;
-
- if (flags)
- return GUSI_error(EOPNOTSUPP);
- if (!chan || !chan->Address().valid)
- return GUSI_error(ENOTCONN); // fuck UNIX semantics; it's impossible for another
- // socket to communicate with this one, anyway
-
- if ((avail = chan->ReadAvail()) == -1)
- return GUSI_error(chan->errno);
-
- // Datagram sockets communicate the sender's address in the first 4 bytes
- // The transfer will be atomic, so only one spin is needed
-
- if (nonblocking && !avail)
- return GUSI_error(EWOULDBLOCK);
-
- errno = 0;
- SPIN(!(avail = chan->Read(&partner, sizeof(UnixChannel *))), SP_DGRAM_READ, 0);
- if (errno)
- return -1;
- else if (avail == -1)
- return GUSI_error(chan->errno);
- else if (avail < int(sizeof(UnixChannel *)))
- return GUSI_error(EINVAL);
-
- if ((avail = chan->Read(&length, sizeof(long))) == -1)
- return GUSI_error(chan->errno);
-
- buflen = min(buflen, length);
-
- if ((avail = chan->Read(buffer, buflen)) == -1)
- return GUSI_error(chan->errno);
-
- chan->DiscardRead(length - buflen);
-
- UncanonizeName(EMUL_Address(partner), from, fromlen);
-
- return avail;
- }
-
- int UnixDgramSocket::sendto(void * buffer, int buflen, int flags, void * to, int tolen)
- {
- UnixSocketAddr * addr;
- UnixChannel * partner;
- int length;
- int avail;
-
- if (flags)
- return GUSI_error(EOPNOTSUPP);
- if (!chan)
- chan = new UnixChannel2(this);
- if (peer)
- partner = peer;
- else {
- addr = CanonizeName(to, tolen);
-
- if (!addr)
- return -1;
-
- partner = LookupName(*addr);
-
- if (!partner)
- return GUSI_error(ECONNREFUSED);
- }
-
- length = sizeof(UnixChannel *) + sizeof(int) + buflen;
-
- if (length > EMUL_BufSize(partner))
- return GUSI_error(EMSGSIZE);
- if ((avail = EMUL_WriteAvail(partner)) == -1)
- return GUSI_error(partner->errno);
- if (avail < length)
- if (nonblocking)
- return GUSI_error(EWOULDBLOCK);
- else
- SPIN((avail=EMUL_WriteAvail(partner)) != -1 && avail<length, SP_DGRAM_WRITE, 0);
-
- if (avail == -1)
- return GUSI_error(partner->errno);
-
- errno = 0;
- SPIN(!(avail = EMUL_Send(partner, chan, buffer, buflen)), SP_DGRAM_WRITE, 0);
- if (errno)
- return -1;
- else if (avail == -1)
- return GUSI_error(partner->errno);
-
- return avail;
- }
-
- /*********************** UnixChannel members ************************/
-
- UnixChannel::UnixChannel(UnixSocket * owner)
- : address(UnixSocketAddr()), sock(owner), nextListener(nil)
- {
- #ifdef EMULATE_CFRONT
- emulated_vtable = UnixChannel_EmulatedVTable;
- #endif
- }
-
- UnixChannel::~UnixChannel()
- {
- if (address.valid)
- UnBind();
- }
-
- void UnixChannel::UnBind()
- {
- if (address.owned)
- HDelete(address.vRefNum, address.parID, address.name);
- }
-
- int UnixChannel::Version()
- {
- #ifdef EMULATE_CFRONT
- return 3;
- #else
- return 1;
- #endif
- }
-
- Boolean UnixChannel::Bind(UnixSocketAddr & addr)
- {
- short resFile;
- short oldResFile = CurResFile();
- Handle ID;
- UnixSocketID me(this);
- FInfo info;
-
- address = addr;
-
- if (PtrToHand(&me, &ID, sizeof(UnixSocketID)))
- return false;
-
- HDelete(address.vRefNum, address.parID, address.name);
- HCreate(address.vRefNum, address.parID, address.name, 'GU∑I', '∑OCK');
- HCreateResFile(address.vRefNum, address.parID, address.name);
- resFile = HOpenResFile(address.vRefNum, address.parID, address.name, fsRdWrPerm);
-
- if (resFile == -1) {
- DisposeHandle(ID);
- return false;
- }
-
- AddResource(ID, 'GU∑I', GUSIRsrcID, (StringPtr) "\p");
-
- if (ResError()) {
- CloseResFile(resFile);
- HDelete(address.vRefNum, address.parID, address.name);
- DisposeHandle(ID);
- UseResFile(oldResFile);
- return false;
- }
-
- CopyIconFamily(LMGetCurApRefNum(), GUSIRsrcID, resFile, kCustomIconResource);
-
- CloseResFile(resFile);
- UseResFile(oldResFile);
-
- HGetFInfo(address.vRefNum, address.parID, address.name, &info);
- info.fdFlags |= (1 << 10);
- info.fdFlags &= ~(1 << 8);
- HSetFInfo(address.vRefNum, address.parID, address.name, &info);
-
- return true;
- }
-
- Boolean UnixChannel::Connect(UnixChannel * ch)
- {
- if (sock->curListener >= sock->maxListener)
- return false;
-
- switch (sock->state) {
- case SOCK_STATE_LISTENING:
- sock->state = SOCK_STATE_LIS_CON;
- // Fall through
- case SOCK_STATE_LIS_CON:
- if (!sock->lastListener)
- sock->firstListener = ch;
- else
- sock->lastListener->nextListener = ch;
-
- sock->lastListener = ch;
- ++sock->curListener;
-
- sock->Ready();
-
- return true;
- default:
- return false;
- }
- }
-
- Boolean UnixChannel::Accept(UnixChannel * ch)
- {
- if (!sock)
- return true;
-
- sock->peer = ch;
- sock->state = SOCK_STATE_CONNECTED;
-
- sock->Ready();
-
- return true;
- }
-
- int UnixChannel::Read(void * buffer, int len)
- {
- if (sock->status & SOCK_STATUS_NOREAD)
- return GUSI_error(ESHUTDOWN);
-
- Ptr startBuf = (Ptr) buffer;
- int section;
-
- if (sock->validBytes > 0) {
- section = sock->readBufSize-sock->readPos;
-
- if (section > sock->validBytes)
- section = sock->validBytes;
- if (section > len)
- section = len;
-
- BlockMove(sock->readBuf+sock->readPos, buffer, section);
-
- buffer = (char *) buffer + section;
- sock->readPos += section;
- sock->validBytes -= section;
- len -= section;
-
- if (sock->readPos == sock->readBufSize)
- sock->readPos = 0;
- } else if (sock->state != SOCK_STATE_CONNECTED)
- return GUSI_error(ESHUTDOWN);
-
- if (len > 0 && sock->validBytes > 0) {
- section = (len > sock->validBytes) ? sock->validBytes : len;
-
- BlockMove(sock->readBuf, buffer, section);
-
- buffer = (char *) buffer + section;
- sock->readPos += section;
- sock->validBytes -= section;
- }
-
- return (char *) buffer-startBuf;
- }
-
- int UnixChannel::Write(void * buffer, int len)
- {
- if (!sock || (sock->status & SOCK_STATUS_NOWRITE))
- return GUSI_error(ESHUTDOWN);
-
- Ptr startBuf = (Ptr) buffer;
- int avail = sock->readBufSize - sock->validBytes;
- int section = avail - sock->readPos;
-
- if (section > 0) {
- if (section > len)
- section = len;
-
- BlockMove(buffer, sock->readBuf+sock->readPos+sock->validBytes, section);
-
- buffer = (char *) buffer + section;
- sock->validBytes += section;
- len -= section;
- avail -= section;
- }
-
- if (len > 0 && avail > 0) {
- section = (len > avail) ? avail : len;
-
- BlockMove(buffer, sock->readBuf+sock->readPos-avail, section);
-
- buffer = (char *) buffer + section;
- sock->validBytes += section;
- }
-
- len = (char *) buffer-startBuf;
-
- if (len)
- sock->Ready();
-
- return (char *) buffer-startBuf;
- }
-
- int UnixChannel::Send(UnixChannel * from, void * buffer, int len)
- {
- int length = sizeof(UnixChannel *) + sizeof(int) + len;
-
- if (sock->peer && sock->peer != from)
- return GUSI_error(ECONNREFUSED);
-
- if (WriteAvail() < length)
- return 0;
-
- Write(&from, sizeof(UnixChannel *));
- Write(&len, sizeof(int));
-
- return Write(buffer, len);
- }
-
- int UnixChannel::ReadAvail()
- {
- if (sock->status & SOCK_STATUS_NOREAD)
- return GUSI_error(ESHUTDOWN);
-
- return sock->validBytes;
- }
-
- int UnixChannel::WriteAvail()
- {
- if (!sock || (sock->status & SOCK_STATUS_NOWRITE))
- return GUSI_error(ESHUTDOWN);
-
- return sock->readBufSize - sock->validBytes;
- }
-
- int UnixChannel::BufSize()
- {
- return sock->readBufSize;
- }
-
- void UnixChannel::ShutDown(int how)
- {
- switch(how) {
- case 0 :
- sock->status |= SOCK_STATUS_NOREAD;
- break;
- case 1 :
- sock->status |= SOCK_STATUS_NOWRITE;
- break;
- case 2 :
- sock->status |= SOCK_STATUS_NOREAD | SOCK_STATUS_NOWRITE;
- }
- }
-
- void UnixChannel::DiscardRead(int len)
- {
- if (sock->validBytes <= len) {
- sock->validBytes = 0;
- sock->readPos = 0;
- } else {
- sock->validBytes -= len;
- sock->readPos = (sock->readPos+len) % sock->readBufSize;
- }
- }
-
- void UnixChannel::Disconnect()
- {
- if (sock) {
- sock->peer = nil;
- sock->state = SOCK_STATE_UNCONNECTED;
- sock->Ready();
- }
- }
-
- int UnixChannel::GUSI_error(int err)
- {
- errno = err;
-
- return -1;
- }
-
- UnixSocketAddr & UnixChannel::Address()
- {
- return address;
- }
-
- /*********************** UnixChannel2 members ************************/
-
- UnixChannel2::UnixChannel2(UnixSocket * owner)
- : UnixChannel(owner)
- {
- }
-
- #ifndef EMULATE_CFRONT
- int UnixChannel2::Version()
- {
- return 2;
- }
- #endif
-
- void UnixChannel2::Orphan()
- {
- // Sever ties to owner
-
- sock->chan = nil;
- sock = nil;
- }
-
- void UnixChannel2::AbortConnect(UnixChannel * ch)
- {
- UnixChannel * prev = nil;
-
- for (UnixChannel * chan = sock->firstListener; chan; chan = chan->nextListener) {
- if (chan == ch) { // Got it !
- if (prev)
- prev->nextListener = chan->nextListener;
- else
- sock->firstListener = chan->nextListener;
-
- if (!chan->nextListener)
- sock->lastListener = prev;
-
- if (!--sock->curListener)
- sock->state = SOCK_STATE_LISTENING;
-
- sock->Ready();
-
- break;
- }
- prev = chan;
- }
- }
-
- /********************* UnixSocketID members **********************/
-
- UnixSocketID::UnixSocketID(UnixChannel * ch)
- : chan(ch)
- {
- short net;
- short node;
-
- AppleTalkIdentity(net, node);
-
- machine.aNet = net;
- machine.aNode = node;
- machine.aSocket= 0;
-
- if (!hasProcessMgr || GetCurrentProcess(&process)) {
- process.highLongOfPSN = kNoProcess;
- process.lowLongOfPSN = kNoProcess;
- }
- }
-
- Boolean UnixSocketID::Validate()
- {
- UnixSocketID me(nil);
- ProcessInfoRec info;
-
- if (memcmp(&machine, &me.machine, sizeof(AddrBlock)))
- return false;
-
- if (!hasProcessMgr)
- return (!process.highLongOfPSN && !process.lowLongOfPSN);
-
- info.processInfoLength = sizeof(ProcessInfoRec);
- info.processName = nil;
- info.processAppSpec = nil;
-
- return !GetProcessInformation(&process, &info);
- }
-
- /********************* UnixSocketDomain member **********************/
-
- extern "C" void GUSIwithUnixSockets()
- {
- UnixSockets.DontStrip();
- }
-
- Socket * UnixSocketDomain::socket(int type, short)
- {
- UnixSocket * sock = nil;
-
- switch (type) {
- case SOCK_STREAM:
- sock = new UnixStreamSocket();
- break;
- case SOCK_DGRAM:
- sock = new UnixDgramSocket();
- break;
- default:
- GUSI_error(ESOCKTNOSUPPORT);
- }
-
- if (sock && errno) {
- delete sock;
-
- return nil;
- } else
- return sock;
- }
-
- int UnixSocketDomain::choose(int, char * prompt, void *, int flags, void * name, int * namelen)
- {
- struct sockaddr_un * addr = (sockaddr_un *) name;
- sa_constr_file constr;
-
- addr->sun_family = AF_UNIX;
-
- constr.numTypes = 1;
- constr.types[0] = '∑OCK';
-
- *namelen -= 2;
- if (FileSockets->choose(0, prompt, &constr, flags, addr->sun_path, namelen))
- return -1;
-
- *namelen += 2;
-
- return 0;
- }
-
-
- /************************* Name conversions *************************/
-
- static char canonPath[120];
- static UnixSocketAddr canonAddr;
-
- static UnixSocketAddr * CanonizeName(void * name, int len)
- {
- struct sockaddr_un * addr = (sockaddr_un *) name;
-
- if (!name || !len || addr->sun_family != AF_UNIX) {
- GUSI_error(EAFNOSUPPORT);
-
- return nil;
- }
-
- len -= 2;
- memcpy(canonPath, addr->sun_path, len);
-
- canonPath[len] = 0;
- canonAddr = TFileSpec(canonPath);
-
- if (canonAddr.Error())
- return nil;
- else
- canonAddr.valid = true;
-
- return &canonAddr;
- }
-
- static void UncanonizeName(UnixSocketAddr & name, void * addr, int * addrlen)
- {
- struct sockaddr_un * uaddr = (sockaddr_un *) addr;
- char * path = name.FullPath();
- char * end;
- int i;
-
- if (!addr || *addrlen < int(sizeof(short))) {
- if (addrlen)
- *addrlen = 0;
-
- return;
- }
-
- *addrlen -= 2;
- uaddr->sun_family = AF_UNIX;
-
- for (i = 0; i < *addrlen; ++i)
- if (!(uaddr->sun_path[i] = path[i]))
- break;
-
- *addrlen = i+2;
- }
-
- static UnixChannel * LookupName(UnixSocketAddr name)
- {
- short file;
- Handle hdl;
- UnixChannel * cur = nil;
- UnixSocketID id;
-
- file = HOpenResFile(name.vRefNum, name.parID, name.name, fsRdPerm);
-
- if (file != -1) {
- if (hdl = Get1Resource('GU∑I', GUSIRsrcID)) {
- id = **(UnixSocketID **) hdl;
-
- if (id.Validate())
- cur = id.chan;
- }
- CloseResFile(file);
- }
-
- return cur;
- }
-